package cn.jdemo.base.safepoint;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * <a href="https://juejin.cn/post/7139741080597037063"></>
 * 1.使用int类型或范围更小的数据类型作为索引值的循环默认是不会被放置安全点的。这种循环被称为可数循环（Counted Loop）
 *
 * 2.相对应地，使用long或者范围更大的数据类型作为索引值的循环就被称为不可数循环（Uncounted Loop），将会被放置安全点。
 *
 * 结论
 *   在可数循环（Counted Loop）的情况下，HotSpot 虚拟机搞了一个优化，就是等循环结束之后，线程才会进入安全点。
 *   反过来说就是：循环如果没有结束，线程不会进入安全点，GC 线程就得等着当前的线程循环结束，进入安全点，才能开始工作。
 *
 * <a href =""></>
 */
public class Demo {
    public static AtomicInteger num = new AtomicInteger(0);

    /**
     * 代码分析:
     *   按照代码来看，主线程休眠 1000ms 后就会输出结果，但是实际情况却是主线程一直在等待 t1,t2 执行结束才继续执行。
     * 1.启动了两个长的、不间断的循环（内部没有安全点检查）。
     * 2.主线程进入睡眠状态 1 秒钟。
     * 3.在1000 ms之后，JVM尝试在Safepoint停止，以便Java线程进行定期清理，但是直到可数循环完成后才能执行此操作。
     * 4.主线程的 Thread.sleep 方法从 native 返回，发现安全点操作正在进行中，于是把自己挂起，直到操作结束。
     *
     * 输出结果:
     *   Thread-0执行结束!
     *   num=2000000000,cost time:18560
     *   Thread-1执行结束!
     */
    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000000; i++) {
                    num.getAndAdd(1);
                }
                System.out.println(Thread.currentThread().getName()+"执行结束!");
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();
        long start = System.currentTimeMillis();
        Thread.sleep(1000);
        System.out.println("num="+num +",cost time:"+ (System.currentTimeMillis() - start));
    }


}
